package 第十二章多态;

/*
 *   关于java语言当中的多态语法机制：
 *       1、animal、cat、bird之间的关机
 *               cat、bird继承animal类
 *               cat和bird之间没有任何联系
 *
 *       2、面向对象三大特征：封装、继承、多态
 *
 *       3、关于多态中涉及到的几个概念：
 *           向上转型    upcasting       子类-->父类     自动类型转型
 *           向下转型    downcasting     父类-->子类     强制类型转换（需要加强制类型转换）
 *
 *       ****无论向上转型还是向下转型，两种类型之间必须要有继承关系，否则程序编译无法通过****
 *
 *
 *
 *
 *
 *
 * */
public class 多态测试01 {
    public static void main(String[] args) {
        //之前的程序
        Animal a1 = new Animal();
        a1.move();
        cat c1 = new cat();
        c1.move();
        c1.catchmouse();
        bird b1 = new bird();
        b1.move();
        System.out.println('\n' + "*****************我是一条分割分割分割分割线********************" + '\n');
        //使用多态语法机制
        /*
         *   1、animal和cat之间存在继承关系，animal是父类，cat是子类
         *   2、cat is animal。
         *   3、new cat（）创建的对象类型是cat，a2这个引用的数据类型是animal，可见他们进行了类型转换
         *      子类型转换成了父类型，称为向上转型，或者称为自动类型转换，upcasting
         *  4、java中允许这种语法：父类型引用指向子类型的对象
         * */
        Animal a2 = new cat();

        /*
         * 1、java程序分为编译阶段和运行阶段
         * 2、编译无法通过，则无法运行
         * 3、编译阶段编译器检查a2这个引用的数据类型为animal，由于animal.class字节码
         *   当中拥有move（）方法，所以编译通过，这个过程称为***静态绑定***，编译阶段绑定
         *   只有静态绑定成功之后才有后续的运行
         * 4、在程序运行阶段，jvm堆内存当中真实创建的是cat对象，则程序在运行阶段一定会调用cat
         *    对象的move（）方法，此时发生了程序的动态绑定，运行阶段绑定
         * 5、父类型引用指向子类型对象这种机制导致程序在编译阶段和运行阶段绑定两种不同的形态/状态，
         *    这种机制可以称为一种多态语法机制
         * */

        a2.move();          /*cat is walking，运行阶段 调用的一定是cat的move方法，
                                即使cat中没有move方法，
                                调用的也是cat从animal中继承的方法，
                                依旧属于cat中的方法*/


        // a2.catchmouse();     //为什么这条语句不能调用
        /*
         * 在编译阶段编译器检查到a2的类型是属于animal类型
         *  在animal.class字节码文件中无法找到catchmouse()
         *
         * */

        //如果有一个需求要输出a2.catchmouse();
        /*
         * a2类型是无法直接调用catchmouse的，因为a2类型是animal，animal中没有catchmouse这个方法
         * 可以将a2强制类型转换为cat类型
         * a2类型是animal（），为父类，转换成cat（）类型，为子类，需要加强制类型转换符
         *
         * 注意：向下转型也需要两种类型之间必须有继承关系，不然编译报错，
         * 使用向下转换的场景：
         *       当调用的方法是子类中特有的，在父类型中不存在的，必须进行向下转型
         * */
        ((cat) a2).catchmouse();
        cat c2 = (cat) a2;
        c2.catchmouse();
        ((cat) a2).catchmouse();




        /*
         * 以下程序编译可以通过，a3的类是animal，属于父类型，cat属于子类型
         *animal转cat属于向下转型 ，语法正确
         *
         *但是该程序在运行阶段会报错，因为jvm虚拟机堆内存中真实存在的对象时候bird 类型，
         * bird无法转换成cat类型，因为这两种类型之间没有任何继承关系，会出现异常
         * java.lang.ClassCastException，这个异常出现在向下转型时会出现
         *
         * */

        //父类引用指向子类对象（多态）
        /*
        Animal a3 = new bird();
        cat c3 = (cat) a3;
        c3.catchmouse();
        */
        /*
         * 以上错误只会在强制类型转换时才会出现，则强制类型（向下转型）存在安全隐患
         * 向上转型只要编译通过，运行一定不会出问题
         * 向下转型编译通过，但是运行会出现异常
         * 通过instanceof运算符可以解决这个问题
         *
         * 关于instanceof运算符
         *       1、语法格式
         *           （引用 instanceof 数据类型名）
         *
         *       2、执行过程
         *           运算的结果是布尔类型，true/false
         *
         *       3、运算结果
         *           true代表引用属于该数据类型
         *           false代表引用不属于该数据类型
         *java规范中要求：在进行强制类型转换之前，建议采用instanceof运算符进行判断，避免产生错误（java lang classcastexception）
         *
         * */
        System.out.println("**************我是最后一条分割线****************************8");
        Animal a3 = new cat();

        if (a3 instanceof cat) {
            cat c3 = (cat) a3;
            //调用子类中特有的方法
            c3.catchmouse();
        } else if (a3 instanceof bird) {
            bird b2 = (bird) a3;
            //调用子类中特有的方法
            b2.fly();
        }
    }
}
